// REVISED FILE: dbms/ReviewShowcaseTest.java
package com.dbms;

import com.dbms.common.QueryResult;
import com.dbms.storage.BufferPoolManager;
import com.dbms.storage.DiskManager;
import com.dbms.storage.Page;
import com.dbms.transaction.LogManager;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

/**
 * 数据库系统综合功能评审演示测试用例
 * [V3 - 最终版] 主要增强点：
 * 1. 完善语义分析对DELETE语句的合法性检查（如检测不存在的表）
 * 2. 新增缓冲池页面替换的详细日志输出，便于观察LRU策略效果
 * 3. 加入系统目录（_tables_、_columns_）的查询与展示，验证元数据管理能力
 *
 * 执行main方法即可运行完整演示流程，覆盖编译器前端、存储后端、执行引擎及数据持久性验证
 */
public class ReviewShowcaseTest {

    // 测试文件路径定义：按功能模块分离，避免相互干扰
    private static final String COMPILER_DB_FILE = "review_compiler_test.db";    // 编译器测试用数据库文件
    private static final String COMPILER_LOG_FILE = "review_compiler_test.log";  // 编译器测试用日志文件
    private static final String EXECUTION_DB_FILE = "review_execution_test.db";  // 执行引擎测试用数据库文件
    private static final String EXECUTION_LOG_FILE = "review_execution_test.log";// 执行引擎测试用日志文件
    private static final String BUFFER_DB_FILE = "review_buffer_test.db";        // 缓冲池测试用数据库文件
    private static final String BUFFER_LOG_FILE = "review_buffer_test.log";      // 缓冲池测试用日志文件

    /**
     * 程序主入口：组织完整的评审演示流程
     * 流程包括：环境清理 → 编译器功能展示 → 缓冲池功能展示 → 执行引擎与持久性展示
     * @param args 命令行参数（未使用）
     */
    public static void main(String[] args) {
        System.out.println("============== Review Showcase Start ==============");

        // 步骤1：清理历史测试文件，确保测试环境干净
        System.out.println("\n--- 1. Setup: Cleaning previous test environment ---");
        cleanupFiles();
        System.out.println("Environment cleaned.");

        // 步骤2：展示编译器前端功能（词法分析、语法分析、语义分析、执行计划生成）
        System.out.println("\n--- 2. Compiler Frontend Showcase (Lexer, Parser, Semantics, Planner) ---");
        showcaseCompiler();

        // 步骤3：展示存储后端功能（页面管理与缓冲池策略）
        System.out.println("\n--- 3. Storage Backend Showcase (Page Management & Buffer Pool) ---");
        showcaseBufferPool();

        // 步骤4：展示执行后端、系统目录及数据持久性
        System.out.println("\n--- 4. Execution Backend, System Catalog & Persistence Showcase ---");
        showcaseExecutionAndPersistence();

        System.out.println("\n============== Review Showcase End ==============");
    }

    /**
     * 展示编译器前端功能：验证SQL处理的全流程（词法→语法→语义→计划）
     * 包含正确用例和各类错误用例，验证编译器的健壮性和准确性
     */
    private static void showcaseCompiler() {
        CompilerUtil compiler = new CompilerUtil(); // 编译器工具类实例

        // 2.1 多语句正确案例：验证正常SQL的处理流程
        System.out.println("\n--- [2.1] Multi-Statement & Correct Case ---");
        String correctSql =
                "CREATE TABLE students (id INT PRIMARY KEY, name VARCHAR(50));\n" +  // 创建表
                        "INSERT INTO students VALUES (1, 'Alice');\n" +              // 插入数据
                        "SELECT id, name FROM students WHERE id = 1;\n" +             // 查询数据
                        "DELETE FROM students WHERE id = 1;";                         // 删除数据
        compiler.processSql(correctSql); // 执行并展示处理结果

        // 2.2 词法错误案例：验证词法分析器对非法字符的检测能力
        System.out.println("\n--- [2.2] Lexical Error Case ---");
        String lexicalErrorSql = "SELECT * FROM users WHERE id = #invalid_char#;"; // 包含非法字符#
        compiler.processSql(lexicalErrorSql);

        // 2.3 语法错误案例：验证语法分析器对语句格式错误的检测能力（缺少分号）
        System.out.println("\n--- [2.3] Syntax Error Case (Missing Semicolon) ---");
        String syntaxErrorSql = "INSERT INTO students VALUES (2, 'Bob')"; // 缺少结束分号
        compiler.processSql(syntaxErrorSql);

        // 2.4 语义错误案例：验证语义分析器对逻辑错误的检测能力（V3版本增强）
        System.out.println("\n--- [2.4] Semantic Error Cases ---");
        String semanticErrorSql =
                "DELETE FROM non_existent_table WHERE id = 1;\n" + // 错误1：删除不存在的表（V3修复：可正确检测）
                        "INSERT INTO students VALUES (3, 'Charlie', 25);\n" +// 错误2：插入列数与表结构不匹配
                        "SELECT non_existent_column FROM students;\n" +// 错误3：查询不存在的列
                        "INSERT INTO students VALUES ('four', 'David');";// 错误4：插入数据类型与列类型不匹配
        compiler.processSql(semanticErrorSql);
    }

    /**
     * 展示存储后端功能：验证缓冲池管理与页面替换机制（基于LRU策略）
     * 场景包括：缓冲池填充、页面替换触发、缓存命中对LRU列表的影响
     */
    private static void showcaseBufferPool() {
        try {
            // 初始化存储组件：磁盘管理器（物理文件）、日志管理器、缓冲池（大小5页）
            DiskManager diskManager = new DiskManager(BUFFER_DB_FILE);
            LogManager logManager = new LogManager(BUFFER_LOG_FILE);
            BufferPoolManager bpm = new BufferPoolManager(5, diskManager, logManager);
            System.out.println("Components initialized for buffer test. Buffer Pool Size = 5 pages.");

            // 准备测试数据：在磁盘上分配6个页面并写入测试数据
            for (int i = 0; i < 6; i++) {
                diskManager.allocatePage(); // 分配物理页
                byte[] data = new byte[DiskManager.PAGE_SIZE]; // 页面数据缓冲区
                String message = "This is raw data on disk page " + i; // 测试数据
                // 将字符串写入缓冲区（仅填充部分数据，模拟真实场景）
                System.arraycopy(message.getBytes(StandardCharsets.UTF_8), 0, data, 0, message.getBytes().length);
                diskManager.writePage(i, data); // 写入磁盘
            }

            // 阶段1：填充缓冲池（读取前5个页面，缓冲池刚好满）
            System.out.println("\nFetching pages to fill the buffer pool...");
            for (int i = 0; i < 5; i++) {
                Page p = bpm.fetchPage(i); // 从磁盘加载页面到缓冲池
                // 打印当前LRU列表（展示页面访问顺序）
                System.out.println("  -> Fetched Page " + p.getPageId() + ". LRU Replacer: " + bpm.getLruList());
                bpm.unpinPage(i, false); // 解除页面固定（不脏，无需写回）
            }
            System.out.println(bpm.getStats()); // 打印缓冲池统计信息

            // 阶段2：读取第6个页面，触发LRU页面替换（缓冲池已满）
            System.out.println("\nFetching Page 5 (triggers LRU replacement)...");
            Page p5 = bpm.fetchPage(5); // 触发替换（V3增强：内部会打印替换日志）
            System.out.println("  -> Fetched Page " + p5.getPageId() + ". LRU Replacer: " + bpm.getLruList());
            bpm.unpinPage(5, false);
            System.out.println(bpm.getStats());

            // 阶段3：访问已在缓冲池中的页面（Page 2），验证LRU列表更新（最近访问的移至末尾）
            System.out.println("\nAccessing Page 2 (cache hit)...");
            System.out.println("  -> Expecting Page 2 to move to the end of the LRU list.");
            Page p2 = bpm.fetchPage(2); // 缓存命中
            System.out.println("  -> Fetched Page " + p2.getPageId() + ". LRU Replacer: " + bpm.getLruList());
            bpm.unpinPage(2, false);
            System.out.println(bpm.getStats());

        } catch (IOException e) {
            e.printStackTrace(); // 处理磁盘IO异常
        }
    }

    /**
     * 展示执行后端、系统目录及数据持久性
     * 包括：DDL/DML执行、系统目录查询、数据持久化验证（重启后数据恢复）
     */
    private static void showcaseExecutionAndPersistence() {
        DbmsCore dbms = null; // 数据库核心实例
        try {
            // 4.1 初始化执行测试环境
            System.out.println("\n--- [4.1] Initializing Core Components for Execution Test ---");
            dbms = new DbmsCore(EXECUTION_DB_FILE, EXECUTION_LOG_FILE);
            System.out.println("DBMS Core initialized on a clean database.");

            // 创建测试表users
            System.out.println("\n[A] Executing: CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100));");
            printResult(dbms.processSql("CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100));"));

            // 4.2 系统目录展示（V3新增）：查询元数据表验证表结构信息
            System.out.println("\n--- [4.2] System Catalog Showcase ---");
            System.out.println("Querying system catalog '_tables_'"); // 系统表：存储所有用户表信息
            printResult(dbms.processSql("SELECT * FROM _tables_ ;"));
            System.out.println("\nQuerying system catalog '_columns_'"); // 系统表：存储所有列信息
            printResult(dbms.processSql("SELECT * FROM _columns_ ;"));


            // 4.3 数据操作演示：插入、查询、删除
            System.out.println("\n--- [4.3] Data Manipulation ---");
            System.out.println("[B] Executing: INSERT INTO users VALUES (1, 'Alice');");
            printResult(dbms.processSql("INSERT INTO users VALUES (1, 'Alice');"));
            System.out.println("[B] Executing: INSERT INTO users VALUES (2, 'Bob');");
            printResult(dbms.processSql("INSERT INTO users VALUES (2, 'Bob');"));
            System.out.println("[B] Executing: INSERT INTO users VALUES (3, 'Charlie');");
            printResult(dbms.processSql("INSERT INTO users VALUES (3, 'Charlie');"));

            System.out.println("\n[C] Executing: SELECT * FROM users; (SeqScan & Project)");
            printResult(dbms.processSql("SELECT * FROM users;")); // 全表扫描+投影

            System.out.println("\n[D] Executing: SELECT name FROM users WHERE id = 2; (SeqScan, Filter, Project)");
            printResult(dbms.processSql("SELECT name FROM users WHERE id = 2;")); // 扫描+过滤+投影

            System.out.println("\n[E] Executing: DELETE FROM users WHERE id = 1;");
            printResult(dbms.processSql("DELETE FROM users WHERE id = 1;")); // 删除操作

            System.out.println("\n[F] Verifying deletion with SELECT * FROM users;");
            printResult(dbms.processSql("SELECT * FROM users;"));

        } finally {
            // 4.4 关闭数据库，确保数据持久化到磁盘
            if (dbms != null) {
                System.out.println("\n--- [4.4] Shutting down DBMS to persist data... ---");
                dbms.shutdown(); // 关闭时会刷新缓冲池数据到磁盘
                System.out.println("Shutdown complete.");
            }
        }

        // 4.5 验证数据持久性：重启数据库，检查数据是否恢复
        System.out.println("\n--- [4.5] Verifying Persistence after Restart ---");
        System.out.println("Restarting DBMS and loading existing database files...");
        DbmsCore restartedDbms = new DbmsCore(EXECUTION_DB_FILE, EXECUTION_LOG_FILE); // 从已有文件重启

        System.out.println("\nVerifying data from previous session...");
        System.out.println("Executing: SELECT * FROM users;");
        System.out.println("Expected to see records for Bob (id=2) and Charlie (id=3).");
        QueryResult result = restartedDbms.processSql("SELECT * FROM users;");
        printResult(result);

        // 验证持久性测试结果
        if (result.tuples.size() == 2) {
            System.out.println("✅ Persistence Test PASSED: Data was correctly reloaded after shutdown.");
        } else {
            System.out.println("❌ Persistence Test FAILED: Data was lost after shutdown.");
        }
        restartedDbms.shutdown(); // 关闭重启后的数据库
    }

    /**
     * 辅助方法：清理所有测试生成的数据库文件和日志文件
     * 确保每次测试从干净的环境开始
     */
    private static void cleanupFiles() {
        new File(COMPILER_DB_FILE).delete();
        new File(COMPILER_LOG_FILE).delete();
        new File(EXECUTION_DB_FILE).delete();
        new File(EXECUTION_LOG_FILE).delete();
        new File(BUFFER_DB_FILE).delete();
        new File(BUFFER_LOG_FILE).delete();
    }

    /**
     * 辅助方法：格式化打印查询结果（QueryResult）
     * 成功时打印数据和消息，失败时打印错误信息
     * @param result 待打印的查询结果对象
     */
    private static void printResult(QueryResult result) {
        if (result == null) return;
        if (result.isSuccess) {
            // 打印结果集中的所有数据行（若有）
            if (result.schema != null && !result.tuples.isEmpty()) {
                result.tuples.forEach(System.out::println);
            }
            System.out.println("-> " + result.message.trim()); // 打印成功消息
        } else {
            System.err.println("-> ERROR: " + result.message.trim()); // 打印错误消息
        }
    }
}